/**
 * 查找dom:  x("#id"), x(".class"), x("div")
 * 事件绑定： x("#id").on("click", function(ev){});
 *           x("#id").on("click", "li", function(ev){})
 * 事件注销： x("#id").off("click");
 * 事件注销： x("#id").off("click", index);  //这里的index是指注册的第几次点击事件，用于指定点击事件的
 * 执行一次的事件绑定： x("#id").on("click", function(){})
 */

var xq = function(){

    return {
        elems: [],
        length: 0,
        
        /**
         * 参数类型： 
         *  1,  cssSelector String
         *  2,  dom元素
         *  3,  html
         * 
         * @param {*} cssSelector 
         */
        init: function(cssSelector){
            var es = [];
            if(typeof cssSelector == 'string' ){
                cssSelector = cssSelector.replace(/^\s+|\s+$/gm,''); //去空格
                var reg = new RegExp('^<([^>\s]+)[^>]*>(.*?<\/\\1>)?$'); //判断是否html

                if(reg.test(cssSelector)){ 
                    var tag = document.createElement("div");
                    tag.innerHTML = cssSelector;
                    es = tag.childNodes;
                }else{
                    es = document.querySelectorAll(cssSelector);
                }

            }
            else{
                var isDOM = ( typeof cssSelector === 'object' ) ?
                    function(obj){
                        return obj instanceof HTMLElement;
                    }(cssSelector) :
                    function(obj){
                        return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string';
                    }(cssSelector);

                if(isDOM){
                    es = [cssSelector];
                }
            }
            return es;
        },
        /**
         * 获取指定元素，如果idx为空，则返回第一个，
         */
        get : function(idx){
            if(typeof idx == 'undefined' && this.elems.length>0){
                return this.elems[0];
            }else if(this.elems.length>0 && idx>=0 && idx<this.elems.length){
                return this.elems[idx];
            }
            return null;
        },
        /**
         * 绑定事件
         * eg: x("#id").on("click", "a", function(){})
         * eg: x("#id").on("click", function(){})
         */
        on : function(eventType, childCssSelector, callback){
            var params = arguments;
            if(params.length==0 || params.length == 1){
                return;
            }
            if(params.length==2 && typeof params[1] == 'function'){
                callback = childCssSelector;
                childCssSelector = "";
            }
            for(var i=0; i<this.elems.length; i++){
                doBind(this.elems[i], eventType, childCssSelector, callback, false);
            }
            return this;
        },

        /**
         * 绑定只执行一次的事件，之后删除绑定
         * eg: x("#id").one("click", "a", function(){})
         * eg: x("#id").one("click", function(){})
         */
        one :  function(eventType, childCssSelector, callback){
            var params = arguments;
            if(params.length==0 || params.length == 1){
                return;
            }
            if(params.length==2 && typeof params[1] == 'function'){
                callback = childCssSelector;
                childCssSelector = "";
            }
            for(var i=0; i<this.elems.length; i++){
                doBind(this.elems[i], eventType, childCssSelector, callback, true);
            }
            return this;
        },

        /**
         * 解除绑定事件
         * x("#id").off("click");
         * x("#id").off("click", idx);  //这里根据你的需要解除指定的第几次绑定的事件
         * 如果是： x("#id").one("click", "a", function(){}) 这种绑定方式， 也是x("#id").off("click");
         */
        off : function (eventType, index){
            for(var i=0; i<this.elems.length; i++){
                removeEvent(this.elems[i], eventType, index);
            }
            return this;
        },
        /**
         * 删除节点自身
         */
        remove: function(){
            for(var i=0; i<this.elems.length; i++){
                try{
                    this.elems[i].parentNode.removeChild(this.elems[i]);
                }catch(err){}
            }
            this.elems = [];
            return this;
        },
        /**
         * 删除所有子节点，不包括自身, 如果指定idx则删除指定节点
         */
        removeChild: function(idx){
            if(typeof idx != 'undefined' && idx>=0 && idx < this.elems.length){
                this.elems[i].removeChild(this.elems[idx]);
            }else{
                for(var i=0; i<this.elems.length; i++){
                    this.elems[i].innerHTML="";
                }
            }
            return this;
        },
        /**
         * 向指定节点下添加子节点，如果指定idx，则插入到指定的位置，如果没有则添加在末尾
         */
        append : function(node, idx){
            
            for(var i=0; i<this.elems.length; i++){
                var elem = this.elems[i];
                if(typeof idx != 'undefined' && idx>=0 && idx < elem.childNodes.length){
                    var target = elem.childNodes[idx];
                    elem.insertBefore(node, target);
                }else{ 
                    elem.appendChild(node);
                }
            }
            
            return this;
        },
        /**
         * 插入到指定节点的前面
        */
        appendBefore: function(node){
            for(var i=0; i<this.elems.length; i++){
                var elem = this.elems[i];
                elem.parentNode.insertBefore(node, elem);
            }
            return this;
        },
        /**
         * 插入到指定节点后面
         */
        appendAfter: function(node){
            for(var i=0; i<this.elems.length; i++){
                var elem = this.elems[i];
                elem.parentNode.insertAfter(elem);
            }
            return this;
        },
        /**
         * 默认取第0个, 如果指定idx，则返回指定idx的节点的当前位置
         * 返回当前节点的位置, 如果没有节点，则返回-1
         */
        index: function(idx){
            if(typeof idx == 'undefined'){
                 idx = 0;
            }

            if(this.elems.length>0){
                var elem = this.elems[idx];
                var children = elem.parentNode.childNodes;
                for(var i=0; i<children.childNodes; i++){
                    if(cildNodes[i]==elem){
                        return i;
                    }
                }
            }
            return -1;
        },
        /**
         * 如果htmlStr为空则获取html值
         * 如果html不为空，则添加到指定节点里面
         */
        html: function(htmlStr){
            if(typeof htmlStr == 'undefined'){
                return this.elems[0].innerHTML;
            }else{
                for(var i=0; i<this.elems.length; i++){
                    this.elems[i].innerHTML = htmlStr;
                }
                return this;
            }
        },
        val: function(value){
            if(typeof value == 'undefined'){
                return this.elems[0].value;
            }else{
                for(var i=0; i<this.elems.length; i++){
                    this.elems[i].value = value;
                }
                return this;
            }
        },
        /**
         * 返回以{key: value}形式返回form数据
         */
        form: function(){
            var form = {};

            function add(name, value){
                if(name){
                    var value = ipt.value;
                    if(name.indexOf("[]")>-1 && name.substring(name.length-2) == '[]'){
                        var name1 = name.substring(name.length-2);
                        if(!form[name1]){
                            form[name1] = [];
                        }
                        form[name1].push(value);
/*
                        if(!form[name]){
                            form[name] = [];
                        }
                        form[name].push(value);
                        */
                    }else{
                        form[name] = value;
                    }
                }
            }

            if(this.elems.length>0){
                var elem = this.elems[0];
                var inputs = elem.getElementsByTagName("input");
                var selects = elem.getElementsByTagName("select");
                var textareas = elem.getElementsByTagName("textarea");

                for(var i=0; i<inputs.length; i++){
                    var ipt = inputs[i];
                    if(!ipt.disabled){
                        add(ipt.name, ipt.value);
                    }
                }
                
                for(var i=0; i<selects.length; i++){
                    var select = selects[i];
                    if(!select.disabled){
                        if(select.multiple){
                            var name = select.name+"[]";
                            for(var j = 0; j<select.options.lengt; j++){
                                var option = select.options[j];
                                if(option.selected){
                                    add(name, option.value);
                                }   
                            }
                        }else{
                            add(select.name, select.value);
                        }
                    }
                }

                for(var i=0; i<textareas.length; i++){
                    var textarea = textareas[i];
                    if(!textarea.disabled){
                        add(textarea.name, textarea.value);
                    }
                }

            }
            return {};
        },
        /**
         * 以key=value&k=v的形式返回form表单的数据，并且urlencode
         */
        formUrl: function(){
            var form = this.form();
            return x.toUrlParam(form);
        },
        formData: function(){
            var elem = this.elems[0];
           
            var formData = null;
            if(elem.tagName.toLowerCase() == 'form'){
                formData = new FormData(elem);
            }else{
                var form = elem.querySelector("form");
                if(form){
                    formData = new FormData(form);
                }else{
                    formData = new FormData();
                }
            }
            return formData;
        }
    }
}

var x = function(cssSelector){
    var myxq = new xq();
    var els = myxq.init(cssSelector);
    for(var i=0; i<els.length; i++){
        myxq.elems.push(els[i]);
    }
    myxq.length = els.length; 
    return myxq;
}

/**
 * 添加x对象方法
 * 
 */
/**
 * 合并两个对象，第二个对象将会覆盖第一个对象 
 */
x.extend = function(obj1, obj2){
    if(typeof obj1 != 'object'){
        if(typeof obj2 != 'object'){
            return {};
        }else{
            return obj2;
        }
    }
    
    if(typeof obj2 != 'object'){
        return {}; 
    }

    for(var key in obj2){
        obj1[key]=obj2[key];
    }    
    return obj1;
}

/**
 * 发送ajax请求
 * @param {
 *      url:  //请求的目标URL, 必须
 *      method: //GET,POST, 默认get
 *      params: //可以是： {}或 string或formData, 可选, string不做任何处理，{}根据contentType转换成对应的数据类型, 如果是formdata则不作处理直接提交
 *      contentType: //application/x-www-form-urlencoded, multipart/form-data, application/json;charset=utf-8  默认application/x-www-form-urlencoded
 *      headers: {key: value, k1: v1}, 可选
 *      resultType: "json", //json, text, xml, 默认json, 如果返回的数据不符合预期，则直接返回原数据
 *      withCredentials: false,   //跨域请求带上cookie, true, false, 默认flase,
 *      success: function(result, xhr){}, 成功回调函数
 *      err: function(result, xhr){}失败回调函数
 *      sync: true, //是否是异步请求，默认为ture, 如果是false，则不需要success,err,回调函数，直接返回结果
 *      cache: false,  //会在url上面添加__r=12312的随机数，用于解决一些浏览器缓存不发送相同的请求
 * } options 
 */
x.ajax = function(options){

    var config = this.extend({
        method: 'GET',
        contentType:  'application/x-www-form-urlencoded',
        resultType: 'json',
        withCredentials: false,
        cache: false,
        sync: true,
    }, options);

    //初始化xhr
    var xhr = null;
    if (window.XMLHttpRequest)
    {
        //  IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
        xhr=new XMLHttpRequest();
    }
    else
    {
        // IE6, IE5 浏览器执行代码
        xhr=new ActiveXObject("Microsoft.XMLHTTP");
    }

    //处理请求url, 是否需要添加随机数
    var url = config.url;
    if(config.cache){
        if(url.indexOf("?")>-1){
            url = url+"&__r="+new Date().getTime();
        }else{
            url = url+"?__r="+new Date().getTime();
        }
    }

    xhr.open(config.method, url, config.sync);
    //设置header
    if(config.headers){
        for(var key in config.headers){
            xhr.setRequestHeader(key, config.headers[key]);
        }
    }

    //处理返回值
    function processResponse(xhr){
        var result = null;
        try{
            if(config.resultType.toLowerCase() == 'xml'){
                result = xhr.responseXML;
            }else{
                result = xhr.responseText;
                if(config.resultType.toLowerCase()  == 'json'){
                    result = x.toJson(result);
                }
            }
        }catch(err){
            console.err(err);
            result = xhr.responseText;
        }
        return result;
    }

    //处理异步请求结果
    if(config.sync){
        xhr.onreadystatechange=function()
        {
            if (xhr.readyState==4){
                if(xhr.status>=200&&xhr.status<300){
                    var result = processResponse(xhr);
                    if(config.success && typeof config.success != 'undefined'){
                        config.success.apply(this, [result, xhr]);
                    }
                }else{
                    if(config.err && typeof config.err != 'undefined'){
                        config.err.apply(this, [xhr]);
                    }
                }

            }
        }
    }

    //设置参数
    if(config.method.toLowerCase()=='post'){
        xmlhttp.setRequestHeader("Content-type", config.contentType);
        var params = config.params;
        if(typeof params == 'object'){

            if(params.constructor.name == 'FormData'){
                xhr.send(params);
            }else{
                if(config.contentType.indexOf("application/x-www-form-urlencoded")>-1){
                    params = this.toUrlParam(params);
                }else if(config.contentType.indexOf("application/json")>-1){
                    params= this.toJsonStr(params);
                }else if(config.contentType.indexOf("multipart/form-data")>-1){
                    params = this.toFormData(params);
                }
            }
        }
        xhr.send(params);
    }else{
        xhr.send();
    }

    //处理同步请求结果
    if(!config.sync){
        var result = processResponse(xhr);
        return result;
    }
    
}
/**
 * 发送get请求
 */
x.get = function(url, successFunc, errFunc){
    this.ajax({
        url: url,
        method: 'GET',
        success: successFunc,
        err: errFunc
    });
}
/**
 * 发送post请求
 */
x.post = function(url, params, successFunc, errFunc){
    this.ajax({
        url: url,
        method: 'POST',
        params: params,
        success: successFunc,
        err: errFunc
    });
}

/**
 * 将对象转换成key=value&key1=value1的字符串形式
 */
x.toUrlParam = function(obj){
    var param = [];
    for(var key in obj){
        var val = obj[key];
        if(Array.isArray(val)){
            val = encodeURIComponent(arr.join(","));
            param.push(val);
        }else{
            val = encodeURIComponent(val);
            param.push(val);
        }
    }
    return param.join("&");
}

/**
 * 转换成formData, 如果浏览器不支持，则返回原对象
 */
x.toFormData = function(obj){
    if(window.formData){
        var formData = new FormData();
        for(var key in obj){
            formData.append(key, obj[key]);
        }
    }
    return obj;
}

/**
 * 将对象转换json字符创
 */
x.toJsonStr = function(jsonObj){
    if(window.JSON) return JSON.stringify(jsonObj);
    else{
        var result = '',
                curVal;
            if (jsonObj === null) {
                return String(jsonObj);
            }
            switch (typeof jsonObj) {
                case 'number':
                case 'boolean':
                    return String(jsonObj);
                case 'string':
                    return '"' + jsonObj + '"';
                case 'undefined':
                case 'function':
                    return undefined;
            }

            switch (Object.prototype.toString.call(jsonObj)) {
                case '[object Array]':
                    result += '[';
                    for (var i = 0, len = jsonObj.length; i < len; i++) {
                        curVal = JSON.stringify(jsonObj[i]);
                        result += (curVal === undefined ? null : curVal) + ",";
                    }
                    if (result !== '[') {
                        result = result.slice(0, -1);
                    }
                    result += ']';
                    return result;
                case '[object Date]':
                    return '"' + (jsonObj.toJSON ? jsonObj.toJSON() : jsonObj.toString()) + '"';
                case '[object RegExp]':
                    return "{}";
                case '[object Object]':
                    result += '{';
                    for (i in jsonObj) {
                        if (jsonObj.hasOwnProperty(i)) {
                            curVal = JSON.stringify(jsonObj[i]);
                            if (curVal !== undefined) {
                                result += '"' + i + '":' +curVal + ',';
                            }
                        }
                    }
                    if (result !== '{') {
                        result = result.slice(0, -1);
                    }
                    result += '}';
                    return result;

                case '[object String]':
                    return '"' + jsonObj.toString() + '"';
                case '[object Number]':
                case '[object Boolean]':
                    return jsonObj.toString();
            }
        return result;
    }
}

/**
 * 将字符串转换成json对象
 */
x.toJson = function(str){
    if(window.JSON) return JSON.parse(str);
    else{
        return eval('(' + str + ')');
    }
}

//end x的对象方法

function doBind(e, eventType, child, callback, one){
    addEvent(e, eventType, function(ev){
        var _this = this;
        if(child){
            var children = e.querySelectorAll(child);
            for(var i=0; i<children.length; i++){
                var child = children[i];
                //console.log(ev.target, child, ev.target == child);
                if(ev.target == child){
                    if(typeof callback == 'function') 
                        callback.apply(this, [ev])
                        //callback(ev);
                }
            }
        }else{
            if(typeof callback == 'function') 
                callback.apply(this, [ev])
                //callback(ev);
        }

        if(one){
            removeEvent(e, eventType); 
        }
    });
}

function addEvent(elem,type,callback) {

    if (elem.addEventListener) {
        // W3C内核
        elem.addEventListener(type,callback, false);
        
    } else if(elem.attachEvent){
        // IE内核
        elem.attachEvent('on'+type,callback);
    } else{
        elem["on"+type]=callback
    }

    if(!elem.eventCaches) {
        elem.eventCaches = {};
    }

    if(!elem.eventCaches[type]){
        elem.eventCaches[type]=[];
    }

    elem.eventCaches[type].push(callback);

}

function removeEvent(elem, type, index){
    if(elem.eventCaches){
        var cbks = elem.eventCaches[type];
        if(cbks && cbks.length>0){

            if(typeof index != 'undefined' && index<this.length){
                doRemoveEvent(elem, type, cbks[index]);
            }else{
                for(var i=0; i<cbks.length; i++){
                    doRemoveEvent(elem, type, cbks[i]);
                }
            }
        }
    }
}

function doRemoveEvent(elem, eventType, callback){
    if(elem.removeEventListener){
        elem.removeEventListener(eventType,callback,false);
    }else if(elem.deattachEvent){
        elem.deattachEvent('on'+eventType,callback);
    }else{
        elem["on" + eventType] = null;
    }
}

export default {x};